package com.wmh.baseservice.common.mybatisplus.query;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.wmh.baseservice.common.ex.ServiceException;
import com.wmh.baseservice.common.utils.CollectionUtil;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;


/**
 * @author 谢骏
 * @date 2023/10/12 14:22
 **/
@Data
@Accessors(chain = true)
@Slf4j
public class FilterReqItem {

    public static final Integer SCOPE_ARRAY_SIZE = 2;

    /**
     * 字段名
     */
    @NotEmpty(message = "FilterReqItem -> prop 不能为空")
    private String prop;

    /**
     * 过滤模式
     */
    @NotNull(message = "FilterReqItem -> mode 不能为空")
    private FilterMode mode;

    /**
     * 过滤值(json)
     */
    @NotEmpty(message = "FilterReqItem -> value 不能为空")
    private String value;

    private <T> void chainBetween(QueryWrapper<T> wrapper, String colName, List<?> scope) {
        checkScopeSize(scope);
        wrapper.between(colName, scope.get(0), scope.get(1));
    }

    private void checkScopeSize(List<?> scope) {
        if (scope.size() != SCOPE_ARRAY_SIZE) {
            throw new ServiceException(StrUtil.format("value size 不兼容 : {}", value));
        }
    }

    public <T> void chainWrapper(QueryWrapper<T> wrapper, String colName) {
        if (StrUtil.isEmpty(colName)) {
            log.warn("FilterReqItem 与数据源不匹配的字段 : {}", prop);
            return;
        }
        switch (mode) {
            case INTEGER_SCOPE:
                this.chainBetween(wrapper, colName, JSON.parseArray(value, Integer.class));
                break;
            case PERCENTAGE_SCOPE:
                List<Double> scope = JSON.parseArray(value, Double.class);
                this.checkScopeSize(scope);
                scope.set(0, scope.get(0) / 100);
                scope.set(1, scope.get(1) / 100);
                this.chainBetween(wrapper, colName, scope);
                break;
            case DATE_SCOPE:
                this.chainBetween(wrapper, colName, JSON.parseArray(value, String.class));
                break;
            case TIMESTAMP_RANGE:
                List<Long> dateRange = CollUtil.map(JSON.parseArray(value, String.class),
                        t -> LocalDateTimeUtil.toEpochMilli(LocalDateTimeUtil.parseDate(t)) / 1000,
                        true);
                this.chainBetween(wrapper, colName, dateRange);
                break;
            case EQ:
            case STR_LIKE:
                wrapper.like(colName, JSON.parseObject(value, String.class));
                break;
            default:
                log.info("FilterReqItem 不兼容的过滤模式: {}", mode);
        }
    }

    public static <T> void chainListWrapper(List<FilterReqItem> paramList, QueryWrapper<T> wrapper, Class<T> entityClass) {
        if (CollUtil.isEmpty(paramList)) {
            return;
        }
        if (entityClass == null) {
            throw new ServiceException("entityClass is not null");
        }
        // 字段名 与 数据库列名映射
        Map<String, String> fieldColMap = CollectionUtil.convertMap(TableInfoHelper.getTableInfo(entityClass).getFieldList(),
                item -> item.getField().getName(), TableFieldInfo::getColumn);
        paramList.forEach(item -> item.chainWrapper(wrapper, fieldColMap.get(item.getProp())));
    }
}
